package com.cybertron.lockdown.spider;

import com.cybertron.lockdown.spider.domain.Seed;
import com.cybertron.lockdown.spider.domain.Site;
import com.thoughtworks.xstream.XStream;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by xiezhouyan on 15-1-10.
 */
public class SiteManager {

    private Logger logger = LoggerFactory.getLogger(this.getClass());


    private Map<String, Site> sites;

    private static final String SITE_XML_FOLDER = "/sites";

    private static final Pattern DOMAIN_PATTERN = Pattern.compile("(?<=http://|\\.)[^.]*?\\.(com|cn|net|org|biz|info|cc|tv)", Pattern.CASE_INSENSITIVE);

    private static final String SPIDER_HOME = System.getProperty("spider.home");

    private List<String> seedUrls;

    public SiteManager() {
        init();
    }

    private void init() {
        File folder;
        if (StringUtils.isNotBlank(SPIDER_HOME)) {
            folder = new File(SPIDER_HOME + SITE_XML_FOLDER);
        } else {
            URL url = SiteManager.class.getResource(SITE_XML_FOLDER);
            folder = new File(url.getFile());
        }
        File[] files = folder.listFiles();
        sites = new LinkedHashMap<String, Site>(files.length);
        XStream xStream = new XStream();
        xStream.processAnnotations(Site.class);
        for (File file : files) {
            if (!file.exists()) {
                continue;
            }
            if (!file.isFile()) {
                continue;
            }
            if (file.isDirectory()) {
                continue;
            }
            if (!file.getName().endsWith(".xml")) {
                continue;
            }
            Site site = (Site) xStream.fromXML(file);
            initSeedUrls(site);
            initListener(site);
            sites.put(site.getDomain(), site);
            logger.info("readed site xml from:" + file.getAbsolutePath());
        }
    }

    private void initSeedUrls(Site site) {
        List<Seed> seeds = site.getSeeds();
        if (seeds == null || seeds.size() == 0) {
            return;
        }
        seedUrls = new ArrayList<String>();
        for (Seed seed : seeds) {
            seedUrls.add(seed.getUrl());
        }
    }

    private void initListener(Site site) {
        String listenerClass = site.getListenerClass();
        try {
            Class<?> clazz = Class.forName(listenerClass);
            Constructor constructor = clazz.getConstructor(Site.class);
            SpiderListener o = (SpiderListener) constructor.newInstance(site);
            site.setListener(o);
        } catch (ClassNotFoundException e) {
            logger.error("init class " + listenerClass + " error", e);
            return;
        } catch (InstantiationException e) {
            logger.error("init class " + listenerClass + " error", e);
            return;
        } catch (IllegalAccessException e) {
            logger.error("init class " + listenerClass + " error", e);
            return;
        } catch (NoSuchMethodException e) {
            logger.error("init class " + listenerClass + " error", e);
            return;
        } catch (InvocationTargetException e) {
            logger.error("init class " + listenerClass + " error", e);
            return;
        }
    }

    public Site getSite(String url) {
        Matcher matcher = DOMAIN_PATTERN.matcher(url);
        matcher.find();
        String domain = matcher.group();
        return sites.get(domain);
    }

    public String[] getSeedUrls() {
        if (seedUrls == null) {
            throw new NullPointerException("seed urls could't not be null");
        }
        String[] urls = new String[seedUrls.size()];
        return seedUrls.toArray(urls);
    }
}
